package edu.isistan.parser;

import java.util.Vector;



import com.thoughtworks.qdox.JavaDocBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.Type;

import edu.isistan.metamodel.Array;
import edu.isistan.metamodel.Collection;
import edu.isistan.metamodel.Composed;
import edu.isistan.metamodel.DataType;
import edu.isistan.metamodel.Primitive;

public class DataTypeMetamodelTransformer {
	private JavaDocBuilder javaDocBuilder;
	public static Vector<Type> collections = new Vector<Type>();
	
	public DataTypeMetamodelTransformer(JavaDocBuilder javaDocBuilder) {
		this.javaDocBuilder = javaDocBuilder;
		collections.add(new Type("java.util.Vector"));
		collections.add(new Type("java.util.List"));
		collections.add(new Type("java.util.ArrayList"));
		collections.add(new Type("java.util.LinkedList"));
	}
	
	/** 
	 * Gets the DataType Operation from a qdox Type
	 * @param dataType the Type of the parameter
	 * @param name the name of the parameter
	 * @return the DataType metamodel
	 */	
	public DataType getDataType(Type dataType, String name, int levels){
		if(levels==0){
			return null;
		}
		if(dataType.isPrimitive() || dataType.toString().equals("java.math.BigDecimal")){
			Primitive primitive = new Primitive(name, dataType.toString(),null);
			return this.checkCardinality(dataType,primitive);
		}
		else if(TypeComparator.getInstance().isWrapper(dataType.toString())
				|| 	dataType.toString().equals("java.lang.String") 
				|| dataType.toString().contains("java.lang.String")){
			Primitive primitive = new Primitive(name, dataType.toString(),null);
			if(!dataType.toString().contains("String"))
				primitive.setWrapper(true);
			return this.checkCardinality(dataType,primitive);			
		}
		else if(collections.contains(dataType)){
			Type innerVectorType = dataType.getActualTypeArguments()[0];
			Collection collection = new Collection(name, this.getDataType(innerVectorType,name,levels-1),null);
			collection.setCollectionType(dataType.getValue());
			collection.setCardinality(-1);
			return collection;						
		}
		else if(dataType.getJavaClass().isEnum()){
			Primitive primitive = new Primitive(name, "java.lang.String",null);	
			return primitive;
		}
		else if(dataType.isResolved()){		
			name = dataType.getJavaClass().getName().substring(dataType.getJavaClass().getName().lastIndexOf('.')+1);
			JavaClass javaClassParameter = javaDocBuilder.getClassByName(name);
			
			JavaField[] fields = javaClassParameter.getFields();
			if(fields.length == 0){
				javaClassParameter = javaDocBuilder.getClassByName(dataType.getJavaClass().getFullyQualifiedName());
				fields = javaClassParameter.getFields();
			}
			
			Vector<DataType> dataTypes = new Vector<DataType>();
			for(JavaField field : fields){
				DataType dType = this.getDataType(field.getType(),field.getName(),levels-1);
				if(field.getComment() != null)
					dType.setDoc(field.getComment());
				dataTypes.add(dType);
			}					
			Composed composed = new Composed(name,dataType.getGenericValue(),dataTypes,javaClassParameter.getComment());
			
			//Se agregan los fields herencia como un datatype mas
			if(dataType.getJavaClass().getSuperClass() != null){
				if(dataType.getJavaClass().getSuperClass().toString().contains("test.discovery")){
					JavaField[] superFields = dataType.getJavaClass().getSuperClass().getJavaClass().getFields();
					for (JavaField superField : superFields)
						composed.addDatatype(this.getDataType(superField.getType(),superField.getName(),JavaParser.PARAMETERS_DEPTH));	
				}
			}
			
			return this.checkCardinality(dataType,composed);
		}

		return null;
	}
			
	/**
	 * Creates a Collection if the Type is an array otherwise stays without changes
	 * @param dataType the Type
	 * @param dataTypeModel internal DataType
	 * @return the DataType
	 */
	private DataType checkCardinality(Type dataType, DataType dataTypeModel){
		if(dataType.isArray()){
			dataTypeModel.setType(dataTypeModel.getType().replace("[]", ""));				
			Array array = new Array(dataTypeModel.getName(), dataTypeModel,"");
			array.setCardinality(dataType.getDimensions());
			return array;
		} else {
			return dataTypeModel;
		}
	}
	
}
